Durante un par de años la narrativa dominante en RAG fue que el vector lo ganaba todo. Bastaba trocear documentos, calcular embeddings, guardarlos en cualquier tienda vectorial y el recall semántico haría el resto. Producción rompe esa promesa rápido: alguien busca un número de pieza, un DNI, un ticket concreto o un acrónimo de tres letras, y el vector devuelve cosas parecidas pero no lo exacto. Quien venía de BM25 puro se topaba con la frustración inversa, consultas reformuladas que compartían sentido pero no vocabulario quedaban fuera del top-k. La búsqueda híbrida es la respuesta operativa: se ejecutan los dos retrievers en paralelo y se fusionan sus rankings. A finales de 2024 ya es el valor por defecto en Elasticsearch, OpenSearch, Weaviate, Qdrant, Vespa y varias capas sobre pgvector, con mejoras de recall típicas entre un veinte y un cuarenta por ciento frente a cualquiera de los dos por separado.
Por qué el híbrido gana donde gana
El vector denso captura similitud semántica aprendida durante el entrenamiento del modelo. Eso lo hace brillante cuando consulta y documento usan vocabulario distinto para la misma idea, cuando hay sinónimos, paráfrasis o cambio de idioma. Lo que no hace bien es distinguir tokens raros que apenas aparecieron en el corpus de entrenamiento. Un SKU como MZ-VL2T0B/AM, un CVE, el número de una sentencia o un nombre propio poco frecuente acaban proyectados en un vecindario semántico genérico y, en una consulta corta, el retriever devuelve documentos que comparten tema pero no el identificador. BM25, en cambio, premia esa literalidad. La fórmula de Okapi pondera frecuencia del término y rareza documental, así que un token raro que coincide palabra por palabra se dispara en el ranking. El precio es que BM25 no sabe nada de semántica: si alguien busca coche y el documento dice automóvil, el solapamiento léxico es cero.
El híbrido no es una técnica nueva, es admitir que las dos señales son complementarias y que lo sensato es combinarlas en tiempo de consulta en lugar de elegir una y rezar. En evaluaciones con conjuntos de oro sobre corpora técnicos, el patrón se repite: consultas con término exacto, números o siglas mejoran drásticamente, consultas puramente conceptuales mejoran poco o nada, y muy pocas empeoran.
La fusión de rankings sin pelearse con los pesos
La parte interesante del híbrido moderno es que ha dejado de depender de combinaciones ponderadas de scores. Mezclar un BM25, cuyo rango depende del corpus y del idioma, con una similitud coseno acotada entre cero y uno era una fuente inagotable de calibraciones frágiles. Reciprocal Rank Fusion, propuesto por Cormack, Clarke y Büttcher en 2009, cambia el marco: en lugar de sumar scores, suma contribuciones del tipo uno partido por una constante más el rango del documento en cada lista. La constante, habitualmente sesenta, amortigua la diferencia entre el primer y el segundo puesto y evita que un retriever dominante aplaste al otro. Como solo usa rangos, RRF es insensible a la escala de los scores originales, y funciona igual fusionando BM25 con vectores densos que fusionando dos modelos densos distintos o añadiendo un reranker cruzado como tercer retriever.
La otra opción habitual es la fusión por alpha, que sí normaliza scores y hace una combinación lineal, típicamente en Weaviate con un parámetro entre cero y uno. Da más control cuando se quiere desplazar deliberadamente el peso hacia una señal, como en catálogos de e-commerce donde la palabra clave debe pesar alto. A cambio, exige ajustar ese alpha por tipo de consulta o colección, y cualquier cambio de modelo de embeddings obliga a recalibrar. RRF es el punto de partida razonable.
Dónde se implementa y con qué ergonomía
Elasticsearch y OpenSearch llevan meses ofreciendo híbrido nativo en la API de búsqueda, con un campo denso configurado en el mapping y un bloque que combina match para texto con knn para el vector en el mismo query. Weaviate expone la operación hybrid con el alpha ya mencionado. Qdrant introdujo colecciones multi-vector con dispersos junto a densos y un FusionQuery que aplica RRF sobre los prefetches. Vespa permite expresar la fusión como expresión de ranking. En pgvector la historia es artesanal pero viable: una CTE con el operador de distancia y otra con ts_rank sobre tsvector, rangos con RANK() OVER, y una consulta final que suma los recíprocos del rango más la constante. Es feo, pero es una sola base de datos.
WITH vec AS (
SELECT id, RANK() OVER (ORDER BY embedding <=> $1) AS r
FROM docs ORDER BY embedding <=> $1 LIMIT 50
),
kw AS (
SELECT id, RANK() OVER (ORDER BY ts_rank(tsv, to_tsquery($2)) DESC) AS r
FROM docs WHERE tsv @@ to_tsquery($2) LIMIT 50
)
SELECT id, SUM(1.0 / (60 + r)) AS rrf
FROM (SELECT * FROM vec UNION ALL SELECT * FROM kw) u
GROUP BY id ORDER BY rrf DESC LIMIT 10;
El patrón se replica literalmente en cualquier motor. Lo que varía es cuánto trabajo queda debajo: en Weaviate o Qdrant se obtiene con una sola llamada y sin preocuparse de la tokenización del BM25; en Postgres hay que decidir configuración de text search, stemmer, diccionarios y stop words, y mantenerlos coherentes con el idioma del contenido. Para corpora multilingües eso empieza a pesar.
El coste real y cuándo no compensa
Hay dos costes que suelen olvidarse. El primero es de indexación: mantener un índice invertido y un índice vectorial duplica espacio y trabajo de ingestión, aunque nada impide reutilizar el mismo almacenamiento de documentos. El segundo es de latencia, menos grave de lo que parece si los dos retrievers corren en paralelo y la fusión es en memoria; el fanout añade milisegundos, no centenas. Donde el híbrido se vuelve caro es cuando se afina por consulta, con reranking cruzado encima y cachés por cada capa.
No todos los casos lo necesitan. Chatbots de soporte con consultas cortas y conversacionales, FAQ en lenguaje natural con corpus del mismo registro, búsquedas cross-lingual donde los embeddings multilingües ya hacen el trabajo, suelen vivir bien con vector puro. El síntoma claro de que hace falta híbrido es ver quejas recurrentes del tipo busqué exactamente este código y no apareció, o un conjunto de oro donde las consultas con término literal tienen precision@10 muy por debajo del promedio.
Tuning y evaluación
La receta operativa es mecánica. Se arranca con RRF de constante sesenta, top-50 por retriever, y se mide contra un conjunto de oro con consultas etiquetadas por tipo. Si un retriever aporta poco, se sube su top-k o se revisa el modelo de embeddings. Si los rangos altos se llenan de duplicados, se deduplica por documento base antes de la fusión. Encima del híbrido conviene colocar un reranker cruzado, tipo Cohere Rerank o bge-reranker, que recibe los top-100 y devuelve top-10 ordenados por un modelo más caro pero más preciso; esa capa absorbe buena parte del ruido que cualquier fusión deja. Y se mide en producción, no con un benchmark genérico, porque las consultas reales tienen distribución de longitudes y tipos que ningún MS MARCO replica.
La búsqueda híbrida no es una técnica puntera, es el nuevo mínimo viable para RAG serio. El vector por sí solo deja fuera la literalidad que los humanos siguen usando cuando saben lo que buscan; BM25 por sí solo deja fuera la flexibilidad semántica que hace que el LLM parezca listo. Combinarlos con RRF cuesta poco, se mantiene igual de bien, y en el noventa por ciento de los corpora mixtos mejora recall sin degradar precision. Lo difícil no es la fusión, es aceptar que la búsqueda léxica clásica, que llevábamos años dando por muerta, sigue siendo la mitad de la respuesta.